% Note:
% Given the target level of future asset bp, the total cost to get this
% asset is bp*( 1+phi/2*(alpha-alpha_bar)^2*sign(bp) )/( 1+rs+alpha*(r-rs)
% ). Or, put in another way, if the hhs save F and choose the domestic bond
% share as alpha, then the they have to pay adjustment cost
% phi/2*(alpha-alpha_bar)^2*|F|. 
% The effective return rate is:
% ( 1+rs+alpha(r-rs) )/( 1+phi/2*(alpha-alpha_bar)^2*sign(F) ) - 1
% If hhs are saving, they want to maximize their effective return rate; if
% they are borrowing, they want to minimize the effective return rate.
classdef PortfolioAdjCost
    properties
        AdjCost {mustBeNumeric}
        r_dom {mustBeNumeric}
        r_ext {mustBeNumeric}
        Share_Target {mustBeNumeric}
    end
    
     methods
        function obj=PortfolioAdjCost(NameValueArgs)
            arguments
                NameValueArgs.AdjCost double        =   1;
                NameValueArgs.r_dom double          =   0.02/4;
                NameValueArgs.r_ext double          =   0.02/4;
                NameValueArgs.Share_Target double   =   0.70;
                
            end
            obj.AdjCost     =   NameValueArgs.AdjCost;
            obj.r_dom       =   NameValueArgs.r_dom;
            obj.r_ext       =   NameValueArgs.r_ext;
            obj.Share_Target=   NameValueArgs.Share_Target;
        end
        function EP=EffectivePrice(obj,Bp,Share_Dom)
            EP      =   ( 1+sign(Bp).*obj.AdjCost/2.*(Share_Dom-obj.Share_Target).^2 )./ ...
                        ( 1+obj.r_ext+Share_Dom.*(obj.r_dom-obj.r_ext) );
        end
        function ER=EffectiveReturn(obj,Bp,Share_Dom)
            ER      =   ( 1+obj.r_ext+Share_Dom.*(obj.r_dom-obj.r_ext) )./ ...
                        ( 1+sign(Bp).*obj.AdjCost/2.*(Share_Dom-obj.Share_Target).^2 );
            ER      =   ER - 1;
        end
        function [S,ER,KAPPA,FR]=OptChoice(obj)
            TempFun_Pos =   @(S,param)-PortfolioAdjCost('r_dom',param(:,1),'r_ext',param(:,2),...
                                                       'AdjCost',obj.AdjCost,'Share_Target',obj.Share_Target)...
                                                       .EffectivePrice(1,S);
            TempFun_Neg =   @(S,param)PortfolioAdjCost('r_dom',param(:,1),'r_ext',param(:,2),...
                                                       'AdjCost',obj.AdjCost,'Share_Target',obj.Share_Target)...
                                                       .EffectivePrice(-1,S);
            N           =   length(obj.r_dom);
            S_Pos       =   VecFun_GoldenSearch(TempFun_Pos,[obj.r_dom,obj.r_ext],-ones(N,1),ones(N,1),1e-7);
            S_Neg       =   VecFun_GoldenSearch(TempFun_Neg,[obj.r_dom,obj.r_ext],-ones(N,1),ones(N,1),1e-7);
            
            ER_Pos      =   obj.EffectiveReturn(1,S_Pos);
            ER_Neg      =   obj.EffectiveReturn(-1,S_Neg);
            
            KAPPA_Pos   =   obj.AdjCost/2 .* (S_Pos - obj.Share_Target).^2;
            KAPPA_Neg   =   obj.AdjCost/2 .* (S_Neg - obj.Share_Target).^2;
            
            FR_Pos      =   obj.r_ext + S_Pos.*(obj.r_dom-obj.r_ext);
            FR_Neg      =   obj.r_ext + S_Neg.*(obj.r_dom-obj.r_ext);
            
            S           =   struct('Pos',S_Pos,'Neg',S_Neg);
            ER          =   struct('Pos',ER_Pos,'Neg',ER_Neg);
            FR          =   struct('Pos',FR_Pos,'Neg',FR_Neg);
            KAPPA       =   struct('Pos',KAPPA_Pos,'Neg',KAPPA_Neg);
        end
        
     end
end